﻿using System;
using System.Configuration;
using System.Linq;
using System.Reflection;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using TheBlog.NhibernateModel.Entities;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Envers.Configuration;
using NHibernate.Envers.Strategy;
using NHibernate.Event;
using NHibernate.Tool.hbm2ddl;
using Configuration = NHibernate.Cfg.Configuration;

namespace TheBlog.NhibernateModel
{
    public class NhibernateInitializer
    {
        public virtual ISessionFactory CreateSessionFactory()
        {
            var configuration = CreateBaseConfiguration();

            return configuration
                .BuildSessionFactory();
        }
        public virtual ISessionFactory CreateSessionFactoryWithAutomaticDbCreate()
        {
            var configuration = CreateBaseConfiguration();
            SetAutomaticDbCreateConfigurations(configuration);
            return configuration
                .BuildSessionFactory();
        }

        private void SetAutomaticDbCreateConfigurations(FluentConfiguration configuration)
        {
            //configuration.ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(true, true));
            //Aradaki farkı set eder.

            configuration.ExposeConfiguration(cfg => new SchemaExport(cfg).Drop(true, true));
            configuration.ExposeConfiguration(cfg => new SchemaExport(cfg).Create(true, true));
        }

        private FluentConfiguration CreateBaseConfiguration()
        {
            return Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2012.ConnectionString(x => x.FromConnectionStringWithKey("MsSql")).ShowSql)
                .ExposeConfiguration(CreateNhEnversConfig())
                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<EntityBase>());
        }

        private static Action<Configuration> CreateNhEnversConfig()
        {
            return nhConf =>
            {
                var enversConf = new NHibernate.Envers.Configuration.Fluent.FluentConfiguration();
                var entityBaseAuiders = typeof(EntityBase).Assembly.GetTypes().Where(type => Attribute.IsDefined(type, typeof(SetAuditAttribute)));
                foreach (var auditeType in entityBaseAuiders)
                {
                    enversConf.Audit(auditeType);
                }
                enversConf.SetRevisionEntity<ArgeLogRevInfo>(d => d.RevNum, d => d.RevDate, new RevisionListener());
                nhConf.SetProperty("nhibernate.envers.store_data_at_delete", "true");
                nhConf.SetProperty("nhibernate.envers.track_entities_changed_in_revision", "true");
                nhConf.IntegrateWithEnvers(enversConf);
            };
        }
    }
}
